/**
 * cantool.c
 *
 * Socket CAN工具程序
 *
 * version: Ver1.0
 * Date   : 2015.11.16
 * Decrip : 原始版本
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <boost/program_options.hpp>
#include <iostream>

#ifndef WIN32
#include <errno.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h>
#include <time.h>
#else
#include <io.h>
#include <time.h>
#include "windows.h"
#endif

#ifndef WIN32
#include "can.h"
#include "raw.h" // for CAN_RAW_FILTER
#endif

#define _VERSION_   "Ver1.0"
#define _OWNER      "reille @ http://velep.com/"

#define true        1
#define false       0

typedef __u8        byte;

typedef union u_canframe_data
{
    __u8            data[8];
    struct
    {
        __u32       dl;
        __u32       dh;
    } s;
} u_canframe_data_t;

static int  send_socket_fd = -1;
static int  recv_socket_fd = -1;

// -----------------------------------------------------------------------------
using namespace std;
using namespace boost::program_options;


static void panic(const char *msg){
    printf(msg);
    exit(1);
}

/**
 * 延时函数
 * @param ms 延时的毫秒数
 */
void delay_ms( const __u32 ms ){
	struct timespec tv;
	tv.tv_sec = ms / 1000;
	tv.tv_nsec = (long)(ms % 1000) * 1000000;
	nanosleep(&tv, NULL);
}

/**
 * 判断字符串是否为数字
 * h@ex: 是否包含十六进制数据
 * @point: 小数点是否有效
 */
bool str_isdigit(const char *s, const bool hex, const bool point){
    int i = 0;

    if (s == NULL || strlen(s) == 0){
        return  false;
    }
    while (s[i] != '\0'){
    	if( (s[i] >='0' && s[i] <= '9') || (point && s[i] == '.') || \
            (hex && (s[i] >= 'a' && s[i] <= 'f')) || (hex && (s[i] >= 'A' && s[i] <= 'F'))){
            i++; 
        }
        else{
            return  false;
        }
    }
    return  true;
}

/**
*
*  Function:1-byte ASC char converts to 1-byte unsigned char number
* In:
* 	i_cAscNumber:the 1-byte ASC char to be converted ('0'~'9','A'~'F')
* Out:
* 	no
* Return:
* 	the converting 1-byte unsigned char number(0x0~0x0F)
* note:
* 	'8' --> 0x08	'D' --> 0x0D
*/
unsigned char Char_No1Hex(char i_cAscChar){
    unsigned char c;
    if (i_cAscChar>='A'){
        c=i_cAscChar-'A'+10;
    }else{
        c=i_cAscChar-48;
    }
    c%=16;
    return c;
}
/**
*Function:2-byte ASC string converts to 1-byte unsigned char number
*In:
*	i_cpStr:pointer of the 2-byte ASC number string("00"~"FF")
*Out:
*	no
*Return:
*	the converting 1-byte unsigned char number
*note:
*	"28" --> 0x28	"7D" --> 0x7D	"AB" --> 0xAB
 */
unsigned char String_Asc2TouChar(char *i_cpStr){
    unsigned char c;
    c = Char_No1Hex(i_cpStr[0])*0x10+Char_No1Hex(i_cpStr[1]);
    return c;
}
/**
*Function:8-byte ASC string converts to 4-byte unsigned long number
*In:
*	i_cpStr:pointer of the 8-byte ASC number string("00000000"~"FFFFFFFF")
*Out:
*	no
*Return:
*	the 4-byte converting unsigned long number
*note:if ASC sring length >8,the get front 8 bytes
*	"00000072" --> 0x72 "789" --> 0x789 "12AC7850" --> 0x12AC7850 "12AC789950" --> 0x12AC7899
*/
unsigned long String_Asc8TouLong(char *i_cpStr){
    int i,j;
    unsigned long lRet,value;
    unsigned char c;
    char tmp_cStr[9];
    for(j=0;j<9;j++) tmp_cStr[j]=0x30;
    j=(int)strlen(i_cpStr);
    if( j<8 ){
        for(i=0;i<j;i++)
            tmp_cStr[8-j+i]=i_cpStr[i];
    }
    else{
        for(i=0;i<8;i++)
            tmp_cStr[i]=i_cpStr[i];
    }
    value=1;
    lRet=0;
    for (i=7;i>=0;i--){
        if (tmp_cStr[i]>=65)
            c=tmp_cStr[i]-65+10;
        else
            c=tmp_cStr[i]-48;
        lRet+=value*c;
        value=value*16;
    }
    return lRet;
}

// -----------------------------------------------------------------------------

typedef struct sys_error_frame{
    __u32       id;
    const char  *err_info;
} s_sys_error_frame_t;

static char g_errframe_info_buf[256] = {0};

static const s_sys_error_frame_t s_sys_error_frame[] = {
    { CAN_ERR_TX_TIMEOUT, "TX timeout (by netdevice driver)"    },
    { CAN_ERR_LOSTARB,    "lost arbitration    / data[0]"       },
    { CAN_ERR_CRTL,       "controller problems / data[1]"       },
    { CAN_ERR_PROT,       "protocol violations / data[2..3]"    },
    { CAN_ERR_TRX,        "transceiver status  / data[4]"       },
    { CAN_ERR_ACK,        "received no ACK on transmission"     },
    { CAN_ERR_BUSOFF,     "bus off"                             },
    { CAN_ERR_BUSERROR,   "bus error (may flood!)"              },
    { CAN_ERR_RESTARTED,  "controller restarted"                },
    { 0,                  NULL}
} ;

bool is_error_frame(const __u32 id){
    int i = 0;
    while (s_sys_error_frame[i].id && s_sys_error_frame[i].err_info != NULL){
        if (id == s_sys_error_frame[i].id){
            return  true;
        }
        i++;
    }
    return  false;
}

const char* get_errframe_info(const __u32 id, const unsigned char* data, const __u8 dlc){
    int l = 0;
    bool unspecified = false;
    char *p = g_errframe_info_buf;
    switch (id){
    case CAN_ERR_TX_TIMEOUT:    sprintf(p, "发送超时");         break;
    case CAN_ERR_LOSTARB:       sprintf(p, "总线仲裁错误");     break;
    case CAN_ERR_CRTL:          
        if (data && dlc >= 2){
            switch (data[1]){
            case CAN_ERR_CRTL_RX_OVERFLOW:  l += sprintf(p + l, "接收缓存溢出");    break;
            case CAN_ERR_CRTL_TX_OVERFLOW:  l += sprintf(p + l, "发送缓存溢出");    break;
            case CAN_ERR_CRTL_RX_WARNING:   l += sprintf(p + l, "接收报警");        break;
            case CAN_ERR_CRTL_TX_WARNING:   l += sprintf(p + l, "发送报警");        break;
            case CAN_ERR_CRTL_RX_PASSIVE:   l += sprintf(p + l, "接收被动错误");    break;
            case CAN_ERR_CRTL_TX_PASSIVE:   l += sprintf(p + l, "发送被动错误");    break;
            default:  unspecified = true;   break; /* unspecified */
            }
        }else{
            unspecified = true;
        }
        if (unspecified){
            l += sprintf(p + l, "CAN控制器错误");
        }
        break;

    case CAN_ERR_PROT:
        if (data && dlc >= 4){
            if (data[2]){
                switch (((const unsigned char*)data)[2]){
                case CAN_ERR_PROT_BIT:      l += sprintf(p + l, "位错误");           break;
                case CAN_ERR_PROT_FORM:     l += sprintf(p + l, "帧格式错误");       break;
                case CAN_ERR_PROT_STUFF:    l += sprintf(p + l, "位填充错误");       break;
                case CAN_ERR_PROT_BIT0:     l += sprintf(p + l, "(接收站)不能发送占有位(dominant bit)"); break;
                case CAN_ERR_PROT_BIT1:     l += sprintf(p + l, "(发送站)不能发送空闲位(recessive bit)"); break;
                case CAN_ERR_PROT_OVERLOAD: l += sprintf(p + l, "总线超负荷");       break;
                case CAN_ERR_PROT_ACTIVE:   l += sprintf(p + l, "主动错误");         break;
                case CAN_ERR_PROT_TX:       l += sprintf(p + l, "传输错误");         break;
                default: unspecified = true;   break; /* unspecified */
                }
            }else{
                unspecified = true;
            }
            if (unspecified && data[3]){
                switch (data[3]){
                //case CAN_ERR_PROT_LOC_SOF:  l += sprintf(p + l, "");         break;
                default: unspecified = true;   break; /* unspecified */
                }
            }
        }else{
            unspecified = true;
        }
        if (unspecified){
            l += sprintf(p + l, "协议违反");
        }
        break;
    case CAN_ERR_TRX:
        break;
    case CAN_ERR_ACK:       sprintf(p, "应答错误");               break;
    case CAN_ERR_BUSOFF:    sprintf(p, "总线关闭");               break;
    case CAN_ERR_BUSERROR:  sprintf(p, "总线错误(可能溢出)");     break;
    case CAN_ERR_RESTARTED: sprintf(p, "CAN控制器重启");          break;
    default: break;
    }
    return  (const char *)p;
}

/**
 * 检查选项是否需要用户输入值
 */
bool option_no_value(const char *option){
    int i = 0;
    const char *options[] = {"-s", "-I", "-g", "-l", ""};
    while (strlen(options[i])){
        if (!strcmp(option, options[i])){
            return  true;
        }
        i++;
    }
    return  false;
}

// -----------------------------------------------------------------------------

bool find_can(const int port){
    char buf[128] = {0};
    sprintf(buf, "/sys/class/net/can%d/dev_id", port);
//       sprintf(buf, "/sys/class/net/can%d/can_bittiming/bitrate", port);
    return  ((access(buf, 0) == 0));
}

/*
 *	bitrate: 250000 or 125000
 */
void set_bitrate(const int port, const int bitrate){
#define TX_QUEUE_LEN		4096 // 使用足够多的发送缓存

#ifndef WIN32
	char	l_c8Command[128] = {0};
	sprintf(l_c8Command, "echo %d > /sys/class/net/can%d/can_bittiming/bitrate", bitrate, port);
	system(l_c8Command);

	// 设置tx_queue_len
	memset(l_c8Command, 0, sizeof(l_c8Command));
	sprintf(l_c8Command, "echo %d > /sys/class/net/can%d/tx_queue_len", TX_QUEUE_LEN, port);
	system(l_c8Command);
#endif
}

void open_can(const int port, const int ){
#ifndef WIN32
    char	l_c8Command[64] = {0};
    sprintf(l_c8Command, "ifconfig can%d up", port);
    system(l_c8Command);
#endif
}

void close_can(const int port){
#ifndef WIN32
    char	l_c8Command[64] = {0};
    sprintf(l_c8Command, "ifconfig can%d down", port);
    system(l_c8Command);
#endif
}

void close_socket(const int sockfd){
#ifndef WIN32
    if (sockfd != -1){
        close(sockfd);
    }
#endif
}
/**
 *
 * 绑定sock，然后监听端口
 * 返回监听 套接字 文件描述符
 */
int socket_listen(const int port){
    int sockfd = -1;

#ifndef WIN32
    struct sockaddr_can _addr;
    struct ifreq _ifreq;
    char buf[256];
    int ret = 0;

     /* 建立套接字，设置为原始套接字，原始CAN协议 */
    sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if (sockfd < 0){
        sprintf(buf, "\n\t打开 socket can%d 错误\n\n", port + 1);
        panic(buf);
        return  -1;
    }
     /* 以下是对CAN接口进行初始化，如设置CAN接口名，即当我们用ifconfig命令时显示的名字 */
    sprintf(buf, "can%d", port);
    strcpy(_ifreq.ifr_name, buf);
    ret = ioctl(sockfd, SIOCGIFINDEX, &_ifreq);
    if (ret < 0){
        sprintf(buf, "\n\t匹配 socket can%d 错误\n\n", port + 1);
        panic(buf);
        return  -1;
    }
    /* 设置CAN协议 */
    _addr.can_family = AF_CAN;
    _addr.can_ifindex = _ifreq.ifr_ifindex;
    /* disable default receive filter on this RAW socket */
    /* This is obsolete as we do not read from the socket at all, but for */
    /* this reason we can remove the receive list in the Kernel to save a */
    /* little (really a very little!) CPU usage.                          */
    //	setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
    /* 将刚生成的套接字与CAN套接字地址进行绑定 */
    ret = bind(sockfd, (struct sockaddr *)&_addr, sizeof(_addr));
    if ( ret < 0){
        close_socket(sockfd);
        sprintf(buf, "\n\t绑定 socket can%d 错误\n\n", port + 1);
        panic(buf);
        return  -1;
    }
#endif
    return  sockfd;
}

int set_can_filter(void){
/**
 * struct can_filter - CAN ID based filter in can_register().
 * @can_id:   relevant bits of CAN ID which are not masked out.
 * @can_mask: CAN mask (see description)
 *
 * Description:
 * A filter matches, when
 *
 *          <received_can_id> & mask == can_id & mask
 *
 */
    const int n = 1;
    struct can_filter rfilter[n];

    // 过滤规则：当<received_can_id> & mask == can_id & mask时，接收报文，否则过滤掉.
    // 可以同时添加多条过滤规则

    // 在用来发送CAN帧的CAN_RAW套接字上不接收任何CAN帧
    rfilter[0].can_id   = 0x00000000;
    rfilter[0].can_mask = CAN_EFF_MASK;
    (void)setsockopt(send_socket_fd, SOL_CAN_RAW, CAN_RAW_FILTER, rfilter, n * sizeof(struct can_filter));

    // 在用来接收CAN帧的CAN_RAW套接字上禁用接收过滤规则
    //(void)setsockopt(recv_socket_fd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
    return  0;
}

int set_can_loopback(const int sockfd, const bool lp){
    // 在默认情况下，本地回环功能是开启的，可以使用下面的方法关闭回环/开启功能：
    int loopback = lp;  // 0表示关闭, 1表示开启(默认) 
    (void)setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));

#if 0
    // 在本地回环功能开启的情况下，所有的发送帧都会被回环到与CAN总线接口对应的套接字上。
    // 默认情况下，发送CAN报文的套接字不想接收自己发送的报文，因此发送套接字上的回环功能是关闭的。
    // 可以在需要的时候改变这一默认行为： 
    int ro = 1; // 0表示关闭(默认), 1表示开启
    (void)setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &ro, sizeof(ro)); 
#endif

    return  0;
}

int socket_connect(const int port){
    return  socket_listen(port);
}

void disconnect(int *sockfd){
    if (!sockfd || *sockfd == -1){
        return ;
    }
    close_socket(*sockfd);
    *sockfd = -1;
}

int send_frame(const int sockfd, const __u8* data, const int count){
#ifndef WIN32
    int ret = write(sockfd, (const char*)data, count);
    if (ret > 0){
        tcdrain(sockfd);//不做出错处理，因为网络不支持tcdrain
    }
    return  ret;
#endif
}

int recv_frame(const int sockfd, __u8* buf, const int count, const int timeout_ms){
    struct timeval tv_timeout;
    tv_timeout.tv_sec  = timeout_ms  / 1000;
    tv_timeout.tv_usec = (timeout_ms % 1000) * 1000;
    fd_set fs_read;
    
    FD_ZERO(&fs_read);
    FD_SET(sockfd, &fs_read);	//if fd == -1, FD_SET will block here

    int ret = select((int)sockfd + 1, &fs_read, NULL, NULL, &tv_timeout);
    if (ret == 0){ // recv timeout
        return  0;
    }
    if (ret < 0){ // select error
        return  ret;
    }

#ifndef WIN32
    ret = read(sockfd, (char*)buf, count);
#else
    ret = recv(sockfd, (char*)buf, count, 0);
#endif

    if (ret <= 0){
        return  -1;
    }
    return  ret;
}

// -----------------------------------------------------------------------------

static int   *pframeno = NULL;
static int   port = 0;
static int   bitrate = 250 * 1000;
static __u32 send_frame_id  = 0x1801F456;
static __u32 send_frame_freq_ms = 250;
static int   send_frame_times   = 0;
static __u8  send_frame_data[8] = {0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
static __u8  dlc = 8;
static bool  extended_frame         = true;
static bool  send_frame_id_inc_en   = false;// 帧ID每发送一帧递增
static bool  send_frame_data_inc_en = false;// 发送数据每发送一帧递增
static bool  lp = false;// 本地环回使能开关
static bool  run = true;


/**
 * return 0: normal; return 1: 终止程序运行
 */
int parse_options(int argc, char **argv){
    int  i = 0, j = 0;
    int  v = 0;
    char *p = NULL;
    bool long_option = false;
    bool ok = true;
    for (i = 1; i < argc; i++){
        if (!argv[i]){
            continue;
        	}
        long_option = false;
        p = NULL;

        //printf("--- i = %d, argc = %d, argv[%d]: %s ---\n", i, argc, i, argv[i]);

        if (strstr(argv[i], "--")){ // 长选项         字符串查找
            long_option = true;
            p = strstr(argv[i], "=");
            if (p == NULL){
                return  -1;
            	}
            p += 1;
        	}
        else if (strstr(argv[i], "-")){ // 短选项
            if (option_no_value(argv[i])){     //检查是否输入用户值
                p = argv[i];
            	}
            else{
                if (argc <= (i + 1)){
                    return  -1;
                	}
                p = argv[i + 1];
            	}
        	}
        else{
            return  -1;
        	}
        ok = false;
        if (!strcmp(argv[i], "--help")){
            return  1;
        	}
        else if (!strcmp(argv[i], "-p") || strstr(argv[i], "--port") != NULL){
            v = atoi(p);
            if (v >= 1 && v < 256){
                port = v - 1;
                ok = true;
            	}
        	}
        else if (!strcmp(argv[i], "-b") || strstr(argv[i], "--baud") != NULL) {
            v = atoi(p);
            if (v == 5 || v == 10 || v == 20 || v == 40 || v == 50 || v == 80 || v == 100 || v == 125 || 
                v == 200 || v == 250 || v == 400 || v == 500 || v == 666 || v == 800 || v == 1000){
                bitrate = v * 1000;
                ok = true;
            	}
        	}
        else if (!strcmp(argv[i], "-i") || strstr(argv[i], "--frame-id") != NULL){
            send_frame_id = (__u32)String_Asc8TouLong(p);    //字符串转换为4字节无符号长整形
            if ((send_frame_id & CAN_EFF_MASK)==0 ){
                printf("帧ID错误%X\n",send_frame_id);
                return  -1;
            	}
            send_frame_id &= CAN_EFF_MASK;
            if (is_error_frame(send_frame_id)){
                printf("错误帧ID%X\n",send_frame_id);
                return  -1;
            	}
            ok = true;
        	}
        else if (!strcmp(argv[i], "-d") || strstr(argv[i], "--data") != NULL){
            dlc = 0;
            if (long_option){
                if (!str_isdigit(p, true, false)){
                    return  -1;
                	}
                v = atoi(p);
                if (v < 0 || v > 256){
                    return  -1;
                	}
                send_frame_data[dlc] = (__u8)String_Asc2TouChar(p);
                dlc++;
            	}
            for (j = i + 1; j < argc && dlc < 8; j++){
                //printf("111 i = %d, j = %d, dlc = %d, argc = %d, argv[%d]: %s \n", i, j, dlc, argc, j, argv[j]);

                if (strstr(argv[j], "-") || strstr(argv[j], "--")){
                    j--;
                    break;
                	}
                if (!str_isdigit(argv[j], true, false)){   //判断字符是否为数字，是返回true,否返回false
                    return  -1;
                	}
                v = atoi(argv[j]);
                if (v < 0 || v > 256){
                    return  -1;
                	}
                send_frame_data[dlc] = (__u8)String_Asc2TouChar(argv[j]);    //2字节字符串转换为字节无符号字符ASC数
                dlc++;
            	}
            i = j;
            ok = true;
            if (i >= argc){
                break;
            	}
            //printf("222 i = %d, j = %d, dlc = %d, argc = %d, argv[%d]: %s \n", i, j, dlc, argc, j, argv[j]);
            continue;
        }
        else if (!strcmp(argv[i], "-f") || strstr(argv[i], "--freq") != NULL){
            v = atoi(p);
            if (v >= 1){
                send_frame_freq_ms = v;
                ok = true;
            }
        }
        else if (!strcmp(argv[i], "-t") || strstr(argv[i], "--times") != NULL){
            v = atoi(p);             //字符串转换为整数
            if (v >= 0){
                send_frame_times = v;
                ok = true;
            }
        }
        else if (!strcmp(argv[i], "-s")){
            extended_frame = false;
            ok = true;
        }
        else if (!strcmp(argv[i], "-I")){
            send_frame_id_inc_en = true;
            ok = true;
        }
        else if (!strcmp(argv[i], "-g")){
            send_frame_data_inc_en = true;
            ok = true;
        }
        else if (!strcmp(argv[i], "-l")){
            lp = true;
            ok = true;
        }
        if (!ok){ // 用户输入了不能解析的选项或参数
            return  -1;
        }
        if (!long_option && !option_no_value(argv[i])){
            i++;
        }
    }
    return  0;
}
int interface,order,spare,name,id,form,DLC,info,dir,DATA;  //标记某一列是否需要隐藏

void  printf_head(void){
    printf("\n");
    printf("SOCKET CAN工具程序，COPYRIGHT (C) 2015 %s \n", _OWNER);
    printf("CAN接口号 ：CAN%d        通讯速率 ：%d bps\n\n", port, bitrate);

    // head
//            CAN1 ==> |  000001  |  18:09:00.356  |  发送成功  | 0x1801F456 |  扩展帧  |  8  |  00 01 FF FF FF FF FF FF  | BMS ==> 充电机
	   if(!interface)
		   printf("+------------+");
	   if(!order)
		   printf("+----------+");
		if(!spare)
			printf("+---------------------+");;
		if(!name)
			printf("+-------------+");
	   if(!id)
		   printf("+---------------+");
	   if(!form)
		   printf("+------------+");
	   if(!DLC)
		   printf("+--------+");
	   if(!info)
		   printf("+------------------------+");
	   if(!dir)
		   printf("+---------------------------------+");
	   if(!DATA)
		   printf("+---------------------------------+");
	   printf("\n");
//    printf("|  接口(port)   |  序号(order)  |帧间隔时间ms(time)|  名称(name)  |   帧ID(id)  | 帧格式(form)  |   DLC(dlc)  |      数据(data)        |  发送方向(direction)  | 数据含义(DATA)\n");
	   if(!interface)
    		printf("| 接口(port) |");
    if(!order)
    		printf("|序号(order)|");
    if(!spare)
    		printf("| 帧间隔时间ms(time) |");
    if(!name)
        	printf("| 名称(name)  |");
	 if(!id)
		   printf("|    帧ID(id)   |");
	 if(!form)
		 	printf("|帧格式(form)|");
	 if(!DLC)
		 	printf("|DLC(dlc)|");
	 if(!info)
		   printf("|      数据(data)        |");
	 if(!dir)
		   printf("| 发送方向(direction) and 报文种类 |");
	 if(!DATA)
	 		printf("|           数据含义(DATA)            |");
	 printf("\n");
	 if(!interface)
		   printf("+------------+");
    if(!order)
		   printf("+----------+");
	 if(!spare)
		 printf("+---------------------+");;
	 if(!name)
	  		printf("+-------------+");
	 if(!id)
		   printf("+---------------+");
	 if(!form)
		   printf("+------------+");
	 if(!DLC)
		   printf("+--------+");
	 if(!info)
		   printf("+------------------------+");
	 if(!dir)
		   printf("+---------------------------------+");
	 if(!DATA)
		   printf("+---------------------------------+");
	 printf("\n");
}

/**
 * 每调用一次本函数，帧序号自加1
 */
static __u8 frameNUm,frame_type,pre_frame_end;

void printf_frame(const __u32 frame_id, const unsigned char *data, const __u8 len,
    const bool extended, 
    const bool ok_flag, 
    const bool sendflag){
    int i = 0, l = 0;
    char buf[128] = {0};
    char timestamp[128] = {0};
    struct timeval tv;
    __u32 no = *pframeno;
    l = 0;
    for (i = 0; data && i < len && i < 8; i++){
        l += sprintf(buf + l, "%02X ", data[i]);
    }
    /* 时间字符串 */
    l = 0;
    (void)gettimeofday(&tv, NULL);         // 获取当前时间
    (void)strftime(timestamp, 128, "%X", localtime(&tv.tv_sec));
    l = strlen(timestamp);
    (void)sprintf(timestamp + l, ".%03ld", tv.tv_usec/1000);
    if(!interface)
    	printf("   CAN%d %s  |",port,sendflag ? "==>" : "<==");
    if(!order)
    	printf("| %7u  |",no);
    if(!spare)
    	printf("|    %s    |",timestamp);

    if (1 && is_error_frame(frame_id)){
    	if(!name)
    		printf("|   %s  |","总线错误");
    	if(!id)
    		printf("|  0x%08X   |",frame_id);
    	if(!form)
    		printf("|  %s   |", "错误帧");
    	if(!DLC)
    		printf("|  %u  |",len);
    	if(!info)
    	printf("| %s x %s |",buf,get_errframe_info(frame_id, data, len));
    }else{
    	if(!name)
			printf("|   %s  |",ok_flag ? (sendflag ? "发送成功" : "接收成功") : (sendflag ? "发送失败" : "接收失败"));
		if(!id)
			printf("|   0x%08X   |",frame_id);
		if(!form)
			printf("|   %s  |", extended ? "扩展帧" : "标准帧");
		if(!DLC)
			printf("|   %u   |",len);
		if(!info)
		printf("|%s|",buf);
     }
    unsigned int frame  = frame_id;
    unsigned int pgn  = frame_id;
    if(!dir){
		if((frame & 0x000000ff)  == 0x56){
			 printf("|充电机 ==> BMS ");
		 }else if((frame & 0x000000ff) == 0xF4){
			 printf("|充电机 <== BMS ");
		 }else{
			 printf("|      错误id     |\n");
		 }
		char character[2]={0};
		__u8 ch1,ch2,ch3,ch4,ch5,ch6,ch7,ch8;
		unsigned int index=0;


		switch((pgn & 0x00ff0000) >> 8){
		case 9728:                                    //18 26 F456
			printf("  CHM充电机握手  |");                 //01 01 00
			if(!DATA){
				printf("| 版本号v1.1 |");
			}
			break;
		case 9984:                                     //182756F4
			printf("  BHM车辆握手  |");
			if(!DATA){                                 //42 0E  365V
				while(index < 5){
					bzero(character,sizeof(character));
					for(int i=0;i<2;i++){
						if(buf[index]!=' '){
							character[i] = buf[index];
							index++;
						}else{
							index++;
							i--;
						}
					}
					if(index < 4)
						ch1 = String_Asc2TouChar(character);   //42
					else
						ch2 = String_Asc2TouChar(character);   //0E
				}
				printf("|最高允许充电总电压 %d V ",((ch2 << 8) + ch1)/10);
			}
			break;
		case 256:                               //0x1801F456
			printf("  CRM充电机辨识  |");
			if(!DATA){                           //00 01 00 00 00 00 00 00  编号为1
				index = 0;
				while(index < 5){
					bzero(character,sizeof(character));
					for(int i=0;i<2;i++){
						if(index>=3){
							character[i] = buf[index];
							index++;
						}else{
							index++;
							i--;
						}
					}
					printf("发送充电机辨识报文，充电机编号 %d",String_Asc2TouChar(character));
				}
			}
			break;
		case 1792:                                // 1807F456
			printf("CTS充电机发送时间同步信息|");      //  01 02 03 04 05 E1 07     2017 5 4 3 2 1
			if(!DATA){
				index = 0;
				while(index < 20){
					bzero(character,sizeof(character));
					for(int i=0;i<2;i++){
						if(buf[index]!=' '){
							character[i] = buf[index];
							index++;
						}else{
							index++;
							i--;
						}
					}
					if(index == 2)
						ch1 = String_Asc2TouChar(character);
					else if(index == 5)
						ch2 = String_Asc2TouChar(character);
					else if(index == 8)
						ch3 = String_Asc2TouChar(character);
					else if(index == 11)
						ch4 = String_Asc2TouChar(character);
					else if(index == 14)
						ch5 = String_Asc2TouChar(character);
					else if(index == 17)
						ch6 = String_Asc2TouChar(character);
					else
						ch7 = String_Asc2TouChar(character);
				}
				printf("%d 年 %d 月 %d 日 %d 时 %d 分 %d 秒",((ch7<<8) + ch6),ch5,ch4,ch3,ch2,ch1);
			}
			break;
		case 2048:                                  //1808F456
			printf(" CML充电机最大输出能力 |");         //58 1B 20 03 60 09 0A 0F     700 80  160 15
			if(!DATA){
				index = 0;
				while(index < 23){
					bzero(character,sizeof(character));
					for(int i=0;i<2;i++){
						if(buf[index]!=' '){
							character[i] = buf[index];
							index++;
						}else{
							index++;
							i--;
						}
					}
					if(index == 2)
						ch1 = String_Asc2TouChar(character);
					else if(index == 5)
						ch2 = String_Asc2TouChar(character);
					else if(index == 8)
						ch3 = String_Asc2TouChar(character);
					else if(index == 11)
						ch4 = String_Asc2TouChar(character);
					else if(index == 14)
						ch5 = String_Asc2TouChar(character);
					else if(index == 17)
						ch6 = String_Asc2TouChar(character);
					else if(index == 20)
						ch7 = String_Asc2TouChar(character);
					else
						ch8 = String_Asc2TouChar(character);
				}
				printf("最高输出电压%dv最低输出电压%dv最高输出电流%dA最低输出电流%dA",((ch2<<8)+ch1)/10,((ch4<<8)+ch3)/10,400-((ch6<<8)+ch5)/10,400-((ch8<<8)+ch7)/10);
			}
			break;
		case 2304:                               //100956F4
			printf("BRO电池充电准备就绪状态 |");       //AA
			if(!DATA){
				index = 0;
				bzero(character,sizeof(character));
				for(int i=0;i<2;i++){
					character[i] = buf[i];
				}
				ch1 = String_Asc2TouChar(character);
				if(ch1 == 0x00)
					printf("BMS 未做好充电准备");
				else if(ch1 == 0xAA)
					printf("BMS 完成充电准备");
				else if(ch1 == 0xFF)
					printf("   无效    ");
			}
			break;
		case 2560:                             //100AF456
			printf("CRO充电机输出准备就绪状态|");    //AA
			if(!DATA){
			index = 0;
			bzero(character,sizeof(character));
			for(int i=0;i<2;i++){
				character[i] = buf[i];
			}
			ch1 = String_Asc2TouChar(character);
			if(ch1 == 0x00)
				printf("充电机未完成充电准|");
			else if(ch1 == 0xAA)
				printf("充电机完成充电准备");
			else if(ch1 == 0xFF)
				printf("   无效    ");
			}
			break;
		case 4096:                             //0x181056F4      42 0E B0 0E 02  365 24 恒流
			printf(" BCL电池充电需求 |");
			if(!DATA){
				index = 0;
				while(index < 14){
					bzero(character,sizeof(character));
					for(int i=0;i<2;i++){
						if(buf[index]!=' '){
							character[i] = buf[index];
							index++;
						}else{
							index++;
							i--;
						}
					}
					if(index == 2)
						ch1 = String_Asc2TouChar(character);
					else if(index == 5)
						ch2 = String_Asc2TouChar(character);
					else if(index == 8)
						ch3 = String_Asc2TouChar(character);
					else if(index == 11)
						ch4 = String_Asc2TouChar(character);
					else if(index == 14)
						ch5 = String_Asc2TouChar(character);
				}
				printf("电压需求%dV电流需求%dA",((ch2<<8)+ch1)/10,400-((ch4<<8)+ch3)/10);
				if(ch5 == 0x01)
					printf("恒压充电");
				else if(ch5 == 0x02)
					printf("恒流充电");
				else
					printf("错误报文");
			}
			break;
		case 4608:                      //0x1812F456    00 00 AC 0D 00 00 FD FF
			printf(" CCS充电机充电状态 |");
			if(!DATA){
				index = 0;
				while(index < 17){
					bzero(character,sizeof(character));
					for(int i=0;i<2;i++){
						if(buf[index]!=' '){
							character[i] = buf[index];
							index++;
						}else{
							index++;
							i--;
						}
					}
					if(index == 2)
						ch1 = String_Asc2TouChar(character);
					else if(index == 5)
						ch2 = String_Asc2TouChar(character);
					else if(index == 8)
						ch3 = String_Asc2TouChar(character);
					else if(index == 11)
						ch4 = String_Asc2TouChar(character);
					else if(index == 14)
						ch5 = String_Asc2TouChar(character);
					else if(index == 17)
						ch6 = String_Asc2TouChar(character);
				}
				printf("电压输出值%dV电流输出值%dA累计充电时间%dmin",((ch2<<8)+ch1)/10,400-((ch4<<8)+ch3)/10,(ch6<<8)+ch5);
			}
			break;
		case 4864:
			printf("BSM动力蓄电池状态信息|");   // 0x181356F4   04 4E 01 4D 03 00 10
			if(!DATA){
				index = 0;
				while(index < 20){
					bzero(character,sizeof(character));
					for(int i=0;i<2;i++){
						if(buf[index]!=' '){
							character[i] = buf[index];
							index++;
						}else{
							index++;
							i--;
						}
					}
					if(index == 2)
						ch1 = String_Asc2TouChar(character);
					else if(index == 5)
						ch2 = String_Asc2TouChar(character);
					else if(index == 8)
						ch3 = String_Asc2TouChar(character);
					else if(index == 11)
						ch4 = String_Asc2TouChar(character);
					else if(index == 14)
						ch5 = String_Asc2TouChar(character);
					else if(index == 17)
						ch6 = String_Asc2TouChar(character);
					else if(index == 20)
						ch7 = String_Asc2TouChar(character);
				}
				printf("|最高单体动力蓄电池电压所在编号%d,最高动力蓄电池温度%d,最高温度检测点编号%d,最低动力蓄电池温度%d,最低动力蓄电池温度检测点编号%d,",ch1,ch2-50,ch3,ch4-50,ch5);
				if((ch6>>6)==0x00)
					printf("动力蓄电池温度正常,");
				else if((ch6>>6)==0x01)
					printf("动力蓄电池温度过高,");
				else if((ch6>>6)==0x10)
					printf("动力蓄电池温度不可信状态,");

				if(((ch6 &0x30)>>4)==0x00)
					printf("动力蓄电池充电过电流正常,");
				else if(((ch6 &0x30)>>4)==0x01)
					printf("动力蓄电池充电过电流过流,");
				else if(((ch6 &0x30)>>4)==0x10)
					printf("动力蓄电池充电过电流不可信状态,");

				if(((ch6 &0x0C)>>2)==0x00)
					printf("整车动力蓄电池荷电状态SOC正常,");
				else if(((ch6 &0x0C)>>2)==0x01)
					printf("整车动力蓄电池荷电状态SOC过高,");
				else if(((ch6 &0x0C)>>2)==0x10)
					printf("整车动力蓄电池荷电状态SOC过低,");

				if((ch6 & 0x03)==0x00)
					printf("单体动力蓄电池电压正常,");
				else if((ch6 & 0x03)==0x01)
					printf("单体动力蓄电池电压过高,");
				else if((ch6 & 0x03)==0x10)
					printf("单体动力蓄电池电压过低,");

				if(((ch7 & 0x30)>>4)==0x00)
					printf("充电允许:禁止,");
				else if(((ch7 & 0x30)>>4)==0x01)
					printf("充电允许:允许,");
				if(((ch7 & 0x0C)>>2)==0x00)
					printf("动力蓄电池组输出连接器连接状态正常,");
				else if(((ch7 & 0x0C)>>2)==0x01)
					printf("动力蓄电池组输出连接器连接状态不正常,");
				else if(((ch7 & 0x0C)>>2)==0x10)
					printf("动力蓄电池组输出连接器连接状态不可信状态,");
				if((ch7 & 0x03)==0x00)
					printf("动力蓄电池绝缘状态正常");
				else if((ch7 & 0x03)==0x01)
					printf("动力蓄电池绝缘状态不正常");
				else if((ch7 & 0x03)==0x10)
					printf("动力蓄电池绝缘状态不可信状态");
			}
			break;
		case 5376:
			printf("BMV单体动力蓄电池电压|");    	//1c 15 无用
			break;
		case 5632:
			printf(" BMT动力蓄电池温度 |");        //1c 16 无用
			break;
		case 5888:
			printf(" BSP动力蓄电池预留报文 |");    //1c 17 无用
			break;
		case 6400:                            //101956F4
			printf(" BST BMS中止充电 |");
			if(!DATA){
				index = 0;
				while(index < 11){
					bzero(character,sizeof(character));
					for(int i=0;i<2;i++){
						if(buf[index]!=' '){
							character[i] = buf[index];
							index++;
						}else{
							index++;
							i--;
						}
					}
					if(index == 2)
						ch1 = String_Asc2TouChar(character);
					else if(index == 5)
						ch2 = String_Asc2TouChar(character);
					else if(index == 8)
						ch3 = String_Asc2TouChar(character);
					else if(index == 11)
						ch4 = String_Asc2TouChar(character);
				}
				if((ch1>>6)==0x00)
					printf("充电机主动中止:正常,");
				else if((ch1>>6)==0x01)
					printf("充电机中止(收到 CST 帧),");
				else if((ch1>>6)==0x10)
					printf("不可信状态,");
				if(((ch1 & 0x30)>>4) ==0x00)
					printf("未达到单体电压设定值,");
				else if(((ch1 & 0x30)>>4) ==0x01)
					printf("达到单体电压设定值,");
				else if(((ch1 & 0x30)>>4) ==0x10)
					printf("不可信状态,");
				if(((ch1 & 0x0c)>>2) ==0x00)
					printf("未达到总电压设定值,");
				else if(((ch1 & 0x0c)>>2) ==0x01)
					printf("达到总电压设定值,");
				else if(((ch1 & 0x0c)>>2) ==0x10)
					printf("不可信状态,");
				if((ch1 & 0x03) == 0x00)
					printf("未达到所需SOC目标值,");
				else if((ch1 & 0x03) == 0x01)
					printf("达到所需SOC目标值,");
				else if((ch1 & 0x03) == 0x10)
					printf("不可信状态,");

				if((ch2>>6)==0x00)
					printf("充电连接器正常,");
				else if((ch2>>6)==0x01)
					printf("充电连接器故障,");
				else if((ch2>>6)==0x10)
					printf("不可信状态,");
				if(((ch2 & 0x30)>>4) ==0x00)
					printf("BMS元件、输出连接器过温正常,");
				else if(((ch2 & 0x30)>>4) ==0x01)
					printf("BMS元件、输出连接器过温故障,");
				else if(((ch2 & 0x30)>>4) ==0x10)
					printf("不可信状态,");
				if(((ch2 & 0x0c)>>2) ==0x00)
					printf("输出连接器过温故障正常,");
				else if(((ch2 & 0x0c)>>2) ==0x01)
					printf("输出连接器过温故障故障,");
				else if(((ch2 & 0x0c)>>2) ==0x10)
					printf("不可信状态,");
				if((ch2 & 0x03) == 0x00)
					printf("绝缘故障:正常,");
				else if((ch2 & 0x03) == 0x01)
					printf("绝缘故障:故障,");
				else if((ch2 & 0x03) == 0x10)
					printf("不可信状态,");

				if((ch3>>6)==0x00)
					printf("其他故障:正常,");
				else if((ch3>>6)==0x01)
					printf("其他故障:故障,");
				else if((ch3>>6)==0x10)
					printf("不可信状态,");
				if(((ch3 & 0x30)>>4) ==0x00)
					printf("检测点2电压检测故障:正常,");
				else if(((ch3 & 0x30)>>4) ==0x01)
					printf("检测点2电压检测故障:故障,");
				else if(((ch3 & 0x30)>>4) ==0x10)
					printf("不可信状态,");
				if(((ch3 & 0x0c)>>2) ==0x00)
					printf("高压继电器故障:正常,");
				else if(((ch3 & 0x0c)>>2) ==0x01)
					printf("高压继电器故障:故障,");
				else if(((ch3 & 0x0c)>>2) ==0x10)
					printf("不可信状态,");
				if((ch3 & 0x03) == 0x00)
					printf("电池组温度正常,");
				else if((ch3 & 0x03) == 0x01)
					printf("电池组温度过高,");
				else if((ch3 & 0x03) == 0x10)
					printf("不可信状态,");

				if((ch4 & 0x03) == 0x00)
					printf("电流正常,");
				else if((ch4 & 0x03) == 0x01)
					printf("电流超过需求值,");
				else if((ch4 & 0x03) == 0x10)
					printf("不可信状态,");
				if(((ch4 & 0x0c)>>2) ==0x00)
					printf("电压异常:正常");
				else if(((ch4 & 0x0c)>>2) ==0x01)
					printf("电压异常:异常");
				else if(((ch4 & 0x0c)>>2) ==0x10)
					printf("不可信状态");
			}
			break;
		case 6656:
			printf(" CST充电机中止充电 |");
			if(!DATA){
				index = 0;
				while(index < 11){
					bzero(character,sizeof(character));
					for(int i=0;i<2;i++){
						if(buf[index]!=' '){
							character[i] = buf[index];
							index++;
						}else{
							index++;
							i--;
						}
					}
					if(index == 2)
						ch1 = String_Asc2TouChar(character);
					else if(index == 5)
						ch2 = String_Asc2TouChar(character);
					else if(index == 8)
						ch3 = String_Asc2TouChar(character);
					else if(index == 11)
						ch4 = String_Asc2TouChar(character);
				}
				if((ch1 & 0x03) == 0x01)
					printf("达到充电机设定条件中止,");
				if((ch1 & 0x0c)>>2 == 0x01)
					printf("人工中止,");
				if((ch1 & 0x30)>>4 == 0x01)
					printf("故障中止,");
				if((ch1 & 0xc0)>>6 == 0x01)
					printf("BMS 中止(收到 BST 帧),");

				if((ch2 & 0x03) == 0x01)
					printf("充电机急停,");
				if((ch2 & 0x0c)>>2 == 0x01)
					printf("其他故障,");

				if((ch3 & 0x03) == 0x01)
					printf("充电机过温,");
				else if((ch3 & 0x03) == 0x00)
					printf("充电机温度正常,");
				if((ch3 & 0x0c)>>2 == 0x01)
					printf("充电连接器故障,");
				else if((ch3 & 0x0c)>>2 == 0x00)
					printf("充电连接器正常,");
				if((ch3 & 0x30)>>4 == 0x01)
					printf("充电机内部过温,");
				else if((ch3 & 0x30)>>4 == 0x00)
					printf("充电机内部温度正常,");
				if((ch3 & 0xc0)>>6 == 0x01)
					printf("电量不能传送,");
				else if((ch3 & 0xc0)>>6 == 0x00)
					printf("电量传送正常,");

				if((ch4 & 0x03) == 0x01)
					printf("电流不匹配,");
				else if((ch4 & 0x03) == 0x00)
					printf("电流匹配,");
				if((ch4 & 0x0c)>>2 == 0x01)
					printf("电压异常,");

			}
			break;
		case 7168:
			printf(" BSD BMS统计数据 |");            //0x181c56F4
			if(!DATA){
				index = 0;
				while(index < 20){
					bzero(character,sizeof(character));
					for(int i=0;i<2;i++){
						if(buf[index]!=' '){
							character[i] = buf[index];
							index++;
						}else{
							index++;
							i--;
						}
					}
					if(index == 2)
						ch1 = String_Asc2TouChar(character);
					else if(index == 5)
						ch2 = String_Asc2TouChar(character);
					else if(index == 8)
						ch3 = String_Asc2TouChar(character);
					else if(index == 11)
						ch4 = String_Asc2TouChar(character);
					else if(index == 14)
						ch5 = String_Asc2TouChar(character);
					else if(index == 17)
						ch6 = String_Asc2TouChar(character);
					else if(index == 20)
						ch7 = String_Asc2TouChar(character);
				}
				printf("中止荷电状态SOC%d%% 动力蓄电池单体最低电压%fV 动力蓄电池单体最高电压%fV 动力蓄电池最低温度%d 动力蓄电池最高温度%d",ch1,((ch3<<8)+ch2)*0.01,((ch5<<8)+ch4)*0.01,ch6-50,ch7-50);
			}
			break;
		case 7424:
			printf(" CSD充电机统计数据 |");           //0x181dF456
			if(!DATA){
				while(index < 11){
					bzero(character,sizeof(character));
					for(int i=0;i<2;i++){
						if(buf[index]!=' '){
							character[i] = buf[index];
							index++;
						}else{
							index++;
							i--;
						}
					}
					if(index == 2)
						ch1 = String_Asc2TouChar(character);
					else if(index == 5)
						ch2 = String_Asc2TouChar(character);
					else if(index == 8)
						ch3 = String_Asc2TouChar(character);
					else if(index == 11)
						ch4 = String_Asc2TouChar(character);
				}
				printf("累计充电时间%dmin,输出能量%dKMh",((ch2<<8)+ch1),((ch4<<8)+ch3)/10);
			}
			break;
		case 7680:
			printf(" BEM BMS错误报文  |");
			if(!DATA){
				index = 0;
				while(index < 11){
					bzero(character,sizeof(character));
					for(int i=0;i<2;i++){
						if(buf[index]!=' '){
							character[i] = buf[index];
							index++;
						}else{
							index++;
							i--;
						}
					}
					if(index == 2)
						ch1 = String_Asc2TouChar(character);
					else if(index == 5)
						ch2 = String_Asc2TouChar(character);
					else if(index == 8)
						ch3 = String_Asc2TouChar(character);
					else if(index == 11)
						ch4 = String_Asc2TouChar(character);
				}
				if((ch1 & 0x03)==0x01)
					printf("接收 SPN2560=0x00 的充电机辨识报文超时");
				else if((ch1 & 0x0c)>>2 == 0x01)
					printf("接收 SPN2560=0xAA 的充电机辨识报文超时");
				if((ch2 & 0x03)==0x01)
					printf("接收充电机的时间同步和充电机最大输出能力报文超时");
				else if((ch2 & 0x0c)>>2 == 0x01)
					printf("接收充电机完成充电准备报文超时");
				if((ch3 & 0x03)==0x01)
					printf("接收充电机充电状态报文超时");
				else if((ch3 & 0x0c)>>2 == 0x01)
					printf("接收充电机中止充电报文超时");
				if((ch4 & 0x03)==0x01)
					printf("接收充电机充电统计报文超时");
				else
					printf("其他");
			}
			break;
		case 7936:
			printf(" CEM 充电机错误报文 |");
			if(!DATA){
				index = 0;
				while(index < 11){
					bzero(character,sizeof(character));
					for(int i=0;i<2;i++){
						if(buf[index]!=' '){
							character[i] = buf[index];
							index++;
						}else{
							index++;
							i--;
						}
					}
					if(index == 2)
						ch1 = String_Asc2TouChar(character);
					else if(index == 5)
						ch2 = String_Asc2TouChar(character);
					else if(index == 8)
						ch3 = String_Asc2TouChar(character);
					else if(index == 11)
						ch4 = String_Asc2TouChar(character);
				}
				if((ch1 & 0x03)==0x01)
					printf("接收BMS和车辆的辨识报文超时,BRM");
				if((ch2 & 0x03)==0x01)
					printf("接收电池充电参数报文超时,BCP");
				else if((ch2 & 0x0c)>>2 == 0x01)
					printf("接收BMS完成充电准备报文超时,BRO");
				if((ch3 & 0x03)==0x01)
					printf("接收电池充电总状态报文超时,BCS");
				else if((ch3 & 0x0c)>>2 == 0x01)
					printf("接收电池充电要求报文超时,BCL");
				else if((ch3 & 0x30)>>4 == 0x01)
					printf("接收BMS中止充电报文超时,BST");
				if((ch4 & 0x03)==0x01)
					printf("接收BMS充电统计报文超时,BSD");
				else
					printf("其他");
			}
			break;
		case 60416:
			printf("  控制帧   |");
			if(!DATA){
				index = 0;
				while(index < 23){
					bzero(character,sizeof(character));
					for(int i=0;i<2;i++){
						if(buf[index]!=' '){
							character[i] = buf[index];
							index++;
						}else{
							index++;
							i--;
						}
					}
					if(index == 2)
						ch1 = String_Asc2TouChar(character);
					else if(index == 5)
						ch2 = String_Asc2TouChar(character);
					else if(index == 8)
						ch3 = String_Asc2TouChar(character);
					else if(index == 11)
						ch4 = String_Asc2TouChar(character);
					else if(index == 14)
						ch5 = String_Asc2TouChar(character);
					else if(index == 17)
						ch6 = String_Asc2TouChar(character);
					else if(index == 20)
						ch7 = String_Asc2TouChar(character);
					else
						ch8 = String_Asc2TouChar(character);
				}
				if(ch1 == 0x10){
					printf("|请求发送,字节数目%d,数据包数目%d,",(ch3<<8)+ch2,ch4);
				}
				else if(ch1 == 0x11){
					printf("|准备发送,数据包数目%d,下一个要发送的数据包编号%d,",ch2,ch3);
					frameNUm = ch2;
				}else if(ch1 == 0x13){
					printf("|消息结束应答,字节数目%d,数据包数目%d",(ch3<<8)+ch2,ch4);
				}
				switch(ch7){
				case 0x02:													//0x1CEC56F4(485250804)       10 29 00 06 06 00 02 00   0x1CECF456(485291094)   11 06 01 FF FF 00 02 00
					printf("BRM BMS和车辆辨识报文");
					break;
				case 0x06:													//0x1CEC56F4   	 10 0D 00 02 02 00 06 00 		0x1CECF456(485291094)	11 02 01 FF FF 00 06 00
					printf("BCP动力蓄电池充电参数");
					break;
				case 0x11:													//0x1CEC56F4   	 10 09 00 02 02 00 11 00		0x1CECF456(485291094)	11 02 01 FF FF 00 11 00
					printf("BCS电池充电总状态");
					break;
				}
				frame_type = ch7;
			}
			break;
		case 60160:
			printf("  数据帧  |");
			if(!DATA){
				index = 0;
				while(index < 23){
					bzero(character,sizeof(character));
					for(int i=0;i<2;i++){
						if(buf[index]!=' '){
							character[i] = buf[index];
							index++;
						}else{
							index++;
							i--;
						}
					}
					if(index == 2)
						ch1 = String_Asc2TouChar(character);
					else if(index == 5)
						ch2 = String_Asc2TouChar(character);
					else if(index == 8)
						ch3 = String_Asc2TouChar(character);
					else if(index == 11)
						ch4 = String_Asc2TouChar(character);
					else if(index == 14)
						ch5 = String_Asc2TouChar(character);
					else if(index == 17)
						ch6 = String_Asc2TouChar(character);
					else if(index == 20)
						ch7 = String_Asc2TouChar(character);
					else
						ch8 = String_Asc2TouChar(character);
				}
				switch(frame_type){
				case 0x02:													//0x1CEB56F4()         BRM     	01 01 01 00 03 B0 04 FE    02 0B FF FF FF FF FF FF
					if(ch1 == 0x01){
						printf("第%d条,版本号v1.1,电池类型:%x,整车动力蓄电池系统额定容量%dAh,",ch1,ch5,((ch7<<8)+ch6)/10);
					}else if(ch1 == 0x02){
						printf("整车动力蓄电池系统额定总电压%fV",((ch2<<8)+pre_frame_end)*0.1);
					}else
						printf("   无效   ");
					break;
				case 0x06:													//0x1CEB56F4   	    BCP  		01 7C 01 F0 0A 71 01 42		02 0E 6E 9E 00 3A 0C FF
					if(ch1 == 0x01){
						printf("单体动力蓄电池最高允许充电电压%fV,最高允许充电电流%fA,动力蓄电池标称总能量%fKWh,",((ch3<<8)+ch2)*0.01,400-((ch5<<8)+ch4)*0.1,((ch7<<8)+ch6)*0.1);
					}else if(ch1 == 0x02){
						printf("最高允许充电总电压%dV,最高允许温度%dºC,SOC%d%%,整车动力蓄电池总电压%dV",((ch2<<8)+pre_frame_end)/10,ch3-50,((ch5<<8)+ch4)/10,((ch7<<8)+ch6)/10);
					}else
						printf("   无效   ");
					break;
				case 0x11:													//0x1CEB56F4   	    BCS			01 3A 0C A0 0F 46 01 0F		02 00 00 FF FF FF FF FF
					if(ch1 == 0x01){
						printf("充电电压测量值%fV,充电电流测量值%dA,最高单体动力蓄电池电压%fV,组号%d, SOC%d%%",((ch3<<8)+ch2)*0.01,400-((ch5<<8)+ch4)/10,(((ch6 & 0x0f)<<8)+ch7)*0.01,ch6>>4,ch8);
					}else if(ch1 == 0x02){
						printf("估算剩余充电时间%dmin",((ch3<<8)+ch2));
					}else
						printf("   无效   ");
					break;
				}
				if(ch1 != frameNUm)
					pre_frame_end = ch8;
			}
			break;
		}
    }
    printf("|\n");
    no++;
    *pframeno = no;
}

void sig_handler(int signo) {
#ifndef WIN32
    switch(signo){
    case SIGINT:
        run = false;
        printf(".Exit\n");
        break;

    default: break;
    }
#endif
}

void install_sig(void) {
#ifndef WIN32
    signal(SIGINT, sig_handler);
#endif
}

int main(int argc, char **argv){
	options_description desc("储能充电车CAN通信程序 北京福威斯油气技术有限公司 基于DM2016系统构建");
	desc.add_options()("help,h", "显示本帮助信息")
		   ("version,v", "显示版本及编译信息")
			("port,p",value< int >(), "CAN接口信息 0 or 1")
			("baud,b",value< int >(),"CAN通讯波特率")
//			("id,i", value< int >(),"CAN发送帧ID")
			("id,i", value< string >(),"CAN发送帧ID,字母必须大写")
			("data",value< string >(), "发送数据")
			("freq,f",value< int >(), "CAN帧发送时间间隔")
			("time,t",value< int >(), "CAN帧发送次数")
			("s", "指定CAN发送帧为标准帧")
			("I", "帧ID每发送一帧递增")
			("g", "发送数据每发送一帧递增")
			("l", "发送数据时本地环回")
			("unshow", value< vector<string> >(),"不显示某项 port order time name id form dlc data direction information");

	variables_map vm;
	try {
			store(parse_command_line(argc, argv, desc), vm);
			notify(vm);
		} catch (std::exception& ex) {
			cout << ex.what() << endl;
			return 1;
		}
    
		if( vm.count("help") ){
			cout << desc <<endl;
			return 1;
		}
    
		if( vm.count("version") ){
			cout <<"SOCKET CAN工具程序 "<<__DATE__<<endl;
			return 1;
		}
    
		if( vm.count("baud") ){
			bitrate = vm["baud"].as< int >();
		}
		char a[8];
		if( vm.count("id") ){
			for(int m=0;m<8;++m){
				a[m]=vm["id"].as< string >().at(m);
			}
			send_frame_id = String_Asc8TouLong(a);
			printf("%x",send_frame_id);

//		   send_frame_id = vm["id"].as< int >();
			if ((send_frame_id & CAN_EFF_MASK)==0 ){
				printf("帧ID错误%X\n",send_frame_id);
				return  -1;
			}
			send_frame_id &= CAN_EFF_MASK;
			if (is_error_frame(send_frame_id)){
				printf("错误帧ID%X\n",send_frame_id);
				return  -1;
			}
		}
		if( vm.count("time") ){
			send_frame_times = vm["time"].as< int >();
		}
		if( vm.count("freq") ){
			send_frame_freq_ms = vm["freq"].as< int >();
		}
		if( vm.count("s") ){
			extended_frame = false;
		}
		if( vm.count("I") ){
			send_frame_id_inc_en = true;
		}
		if( vm.count("g") ){
			send_frame_data_inc_en = true;
		}
		if( vm.count("l") ){
			lp = true;
		}

		int idlc=0 ,j;
		unsigned int i=0;
		char d[2] = "\0";
		if( vm.count("data") ){
			dlc=0;
			while(idlc < 8){
				bzero(d,sizeof(d));
				for(j=0;j<2;j++){
					if(i < vm["data"].as< string >().size()){
						if((vm["data"].as< string >().at(i)>='0'&&vm["data"].as< string >().at(i)<='9') ||
							(vm["data"].as< string >().at(i)>='a'&&vm["data"].as< string >().at(i)<='f') ||
							(vm["data"].as< string >().at(i)>='A'&&vm["data"].as< string >().at(i)<='F')){
							d[j] = vm["data"].as< string >().at(i);
							i++;
						}else{
							printf("put error!\n");
							exit(0);
						}
					}
				}
				send_frame_data[idlc] = (__u8)String_Asc2TouChar(d);   //   00 01 FF FF FF FF FF FF
				++dlc;
				++idlc;
			}
		}
		vector<string> unshow;
		if( vm.count("unshow") ){
			unshow = vm["unshow"].as< vector<string> >();
		}

		int Numunshow = unshow.size();
		if(Numunshow < 0 || Numunshow>10){
			printf("put error!\n");
			return -1;
		}
		for(int i=0;i<Numunshow;i++){
			if(!unshow.at(i).compare("port")){
				interface = 1;
			}
			if(!unshow.at(i).compare("order")){
				order = 1;
			}
			if(!unshow.at(i).compare("time")){
				spare = 1;
			}
			if(!unshow.at(i).compare("name")){
				name = 1;
			}
			if(!unshow.at(i).compare("id")){
				id = 1;
			}
			if(!unshow.at(i).compare("form")){
				form = 1;
			}
			if(!unshow.at(i).compare("dlc")){
				DLC = 1;
			}
			if(!unshow.at(i).compare("data")){
				info = 1;
			}
			if(!unshow.at(i).compare("direction")){
				dir = 1;
			}
			if(!unshow.at(i).compare("information")){
				DATA = 1;
			}
		}

		S_CanFrame sendframe, recvframe;
		__u8 *precvframe = (__u8 *)&recvframe;
		u_canframe_data_t *psend_data = (u_canframe_data_t *)sendframe.data;
		const int can_frame_len = sizeof(S_CanFrame);
		if( !vm.count("port")){                                    // 默认为can0
			cout << "参数错误，必须设置port接口号,默认为can0" << endl;
			port = 0;
		}else{
			port = vm["port"].as<int>();
		}
		if( port<0 || port>= 2){         								 // port  接口信息
			printf("参数错误,CAN 接口必须为0或1.\n");
			return -1;
		}
		close_can(port);													 // 必须先关闭CAN，才能成功设置CAN波特率
		set_bitrate(port, bitrate);									    // 操作CAN之前，先要设置波特率
		open_can(port, bitrate);                                  // 打开can
		send_socket_fd = socket_connect(port);
		recv_socket_fd = socket_connect(port);

	   if (send_socket_fd < 0 || recv_socket_fd < 0){
			disconnect(&send_socket_fd);
			disconnect(&recv_socket_fd);
			panic("\n\t打开socket can错误\n\n");
			return  -1;
		}
	 printf_head();                         //显示
    pid_t pid = -1;
    int  status;
    int  ret = 0;
    bool carry_bit = false;					// 进位标志
    int segment_id;//id for shared memo
    set_can_filter();                     //过滤报文
    set_can_loopback(send_socket_fd, lp); //设置本地回环
    memset(&sendframe, 0x00, sizeof(sendframe));
    memset(&recvframe, 0x00, sizeof(recvframe));
    if (extended_frame){															// 指定发送帧类型：扩展帧或标准帧 true 扩展帧 false 标准帧
        sendframe.can_id = (send_frame_id & CAN_EFF_MASK) | CAN_EFF_FLAG;
    }else{
        sendframe.can_id = (send_frame_id & CAN_SFF_MASK);
    }
    sendframe.can_dlc = dlc;
    memcpy(sendframe.data, send_frame_data, dlc);                    //将需要发送的信息拷贝到结构体上
    segment_id = shmget(IPC_PRIVATE, sizeof(int), S_IRUSR | S_IWUSR);// allocate memo
    pframeno = (int *)shmat(segment_id, NULL, 0);						  // attach the memo
    if (pframeno == NULL){
        panic("\n\t创建共享内存失败\n\n");
        return  -1;
    }
    *pframeno = 1;
    run = true;
    pid = fork();
    if(pid == -1){
        panic("\n\t创建进程失败\n\n");
        return  -1;
    }else if(pid == 0){ // 子进程，用于发送CAN帧
        while (run && (send_frame_times > 0)){
            ret = send_frame(send_socket_fd, (const unsigned char *)&sendframe, sizeof(sendframe));
            printf_frame(sendframe.can_id & CAN_EFF_MASK, sendframe.data, sendframe.can_dlc,
                ((sendframe.can_id & CAN_EFF_FLAG) ? true : false),
                ret > 0 ? true : false, true);
            delay_ms(send_frame_freq_ms);
            if (send_frame_id_inc_en){                     // 判断 帧ID递增
                sendframe.can_id++;
                if (extended_frame){                       //判断是否是标准帧  标准帧false
                    sendframe.can_id = (sendframe.can_id & CAN_EFF_MASK) | CAN_EFF_FLAG;
                }else{
                    sendframe.can_id = (sendframe.can_id & CAN_SFF_MASK);
                	 }
            	}
            if (send_frame_data_inc_en && dlc > 0){       //判断发送数据，每发送一帧递增
                if (dlc > 4 && psend_data->s.dl == ((__u32)0xFFFFFFFF)){
                    carry_bit = true;							// 发生进位   发送完一帧，置位
                	}
                psend_data->s.dl++;
                if (dlc <= 4){
                    if (psend_data->s.dl >= (1u << (dlc * 8))){    //  dlc没有减的地方
                        psend_data->s.dl = 0;
                    	}
                }else if (dlc <= 8){
                    if (carry_bit){
                        psend_data->s.dh++;
                        if (psend_data->s.dh >= (1u << ((dlc - 4) * 8))){
                            psend_data->s.dh = 0;
                        	  }
                        carry_bit = false;
                    	  }
                	}
               }
            send_frame_times--;
          }
        exit(0);
     }
    else{ // 父进程，接收CAN帧
        install_sig();      //终止信号
        while (run){
            memset(precvframe, 0x00, can_frame_len);
            ret = recv_frame(recv_socket_fd, precvframe, can_frame_len, 5 * 1000);
            if (ret > 0){
				printf_frame(recvframe.can_id & CAN_EFF_MASK, recvframe.data, recvframe.can_dlc,
					((recvframe.can_id & CAN_EFF_FLAG) ? true : false),
					true,
					false);
            }
        }
        while(((pid = wait(&status)) == -1) && (errno == EINTR)){
            delay_ms(10);
        }
    }
    disconnect(&send_socket_fd);
    disconnect(&recv_socket_fd);
    shmdt(pframeno);// detach memo
    shmctl(segment_id, IPC_RMID, NULL);// remove
    return  0;
}

// -----------------------------------------------------------------------------
// cantool.c
